package org.m8.auth.model;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import com.xingyuv.jushauth.config.AuthConfig;
import com.xingyuv.jushauth.model.AuthCallback;
import com.xingyuv.jushauth.model.AuthResponse;
import com.xingyuv.jushauth.model.AuthUser;
import com.xingyuv.jushauth.request.AuthRequest;
import com.xingyuv.justauth.AuthRequestFactory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.m8.auth.config.SocialConfig;
import org.m8.auth.config.SocialTypeEnum;
import org.m8.dba.transaction.M8Transactional;
import org.m8.util.JsonUtil;
import org.m8.util.Snowflake;
import org.springframework.stereotype.Service;

import static org.m8.util.exception.ServiceExceptionUtil.exception;
import static org.m8.util.exception.emnus.GlobalErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE;

/**
 * 社交用户绑定service
 *
 * @author yidanjun
 * @date 2024/9/5
 **/
@Service
@Slf4j
public class SocialUserBindService {

    private static final Snowflake snowflake = Snowflake.build(1, 1, 1);

    @Resource
    private SocialUserBindDao socialUserBindDao;

    @Resource
    private AuthRequestFactory authRequestFactory;

    @Resource
    private SocialConfig socialConfig;

    /**
     * 授权获得对应的社交用户
     *
     * @param socialType 社交平台的类型
     * @param code 授权码
     * @param state state
     * @return 授权用户
     */
    @M8Transactional
    public SocialUserBindDO authSocialUser(String socialType, String code, String state, String userId) {
        SocialUserBindDO socialUserBindDO = socialUserBindDao.selectByTypeAndCodeAnState(socialType, code, state);
        if (socialUserBindDO != null) {
            return socialUserBindDO;
        }

        // 请求获取
        AuthUser authUser = this.getAuthUser(socialType, code, state);
        Assert.notNull(authUser, "三方用户不能为空");

        if (StringUtils.isNotBlank(userId)) {
            // 用户id不为空时，删除之前的绑定信息
            socialUserBindDao.deleteByUerIdAndSocialType(userId, socialType);
        }

        // 根据openid和社交类型查询用户绑定社交信息
        socialUserBindDO = socialUserBindDao.queryBySocialTypeAndOpenId(socialType, authUser.getUuid());
        if (socialUserBindDO == null) {
            socialUserBindDO = new SocialUserBindDO();
        }
        socialUserBindDO.setUserId(userId);
        socialUserBindDO.setSocialType(socialType);
        socialUserBindDO.setCode(code);
        socialUserBindDO.setOpenid(authUser.getUuid());
        socialUserBindDO.setState(state);

        if (socialUserBindDO.getId() == null){
            socialUserBindDO.setId(id());
            socialUserBindDao.inert(socialUserBindDO);
        } else {
            socialUserBindDao.updateById(socialUserBindDO);
        }

        return socialUserBindDO;
    }


    /**
     * 绑定用户
     *
     * @param socialUserBindDO
     */
    public void bindUser(SocialUserBindDO socialUserBindDO){
        socialUserBindDao.updateById(socialUserBindDO);
    }
    private AuthUser getAuthUser(String socialType, String code, String state) {
        // 构建请求
        AuthRequest authRequest = buildAuthRequest(socialType);
        AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build();
        // 执行请求
        AuthResponse<?> authResponse = authRequest.login(authCallback);

        log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType,
                JsonUtil.stringify(authCallback), JsonUtil.stringify(authResponse));
        if (!authResponse.ok()) {
            throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg());
        }
        return (AuthUser) authResponse.getData();
    }

    /**
     * 构建 AuthRequest 对象，支持多租户配置
     *
     * @param socialType 社交类型
     * @return AuthRequest 对象
     */
    private AuthRequest buildAuthRequest(String socialType) {
        // 1. 先查找默认的配置项，从 application-*.yaml 中读取
        SocialTypeEnum socialTypeEnum = SocialTypeEnum.valueOfType(socialType);

        AuthRequest request = authRequestFactory.get(socialTypeEnum.getSource());
        Assert.notNull(request, String.format("社交平台(%s) 不存在", socialType));
        // 2.1 构造新的 AuthConfig 对象
        AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(request, "config");
        AuthConfig newAuthConfig = ReflectUtil.newInstance(authConfig.getClass());
        BeanUtil.copyProperties(authConfig, newAuthConfig);
        // 2.2 修改对应的 clientId + clientSecret 密钥
        newAuthConfig.setClientId(socialConfig.getClientId());
        newAuthConfig.setClientSecret(socialConfig.getClientSecret());
        if (socialConfig.getAgentId() != null) { // 如果有 agentId 则修改 agentId
            newAuthConfig.setAgentId(socialConfig.getAgentId());
        }
        // 2.3 设置会 request 里，进行后续使用
        ReflectUtil.setFieldValue(request, "config", newAuthConfig);
        return request;
    }

    private String id(){
        return "Social_" + snowflake.nextIdStr();
    }
}
